const esprima = require('esprima');
const estraverse = require('estraverse');
const escodegen = require('escodegen');

const babylon = require('babylon')
const types = require('@babel/types')
const generate = require('@babel/generator').default
const traverse = require('@babel/traverse').default

var path = require('path');
var fs = require('fs');

// var file = path.join(__dirname, "./birankeji/nvc.js");
var file = path.join(__dirname, "./sample/c.js");

fs.readFile(file, 'utf-8', function(err, data) {
    if (err) {
        res.send('文件读取失败');
    } else {
        // parseCode(data);
        traverse2(data);
    }
});


//根据操作数返回处理结果
function OperaterAll(x,y,operator){
    switch (operator) {
        case "+":
            return x+y;
        case "-":
            return x-y;
        case "*":
            return x*y;
        case "/":
            return x/y;
        case "&":
            return x&y;
        case "|":
            return x|y;
        case "<<":
            return x<<y;
        case ">>":
            return x>>y;
    }
}

//递归操作数据
function OperatorNode(parent, left, right, operator) {
    if(left.hasOwnProperty('operator') && !right.hasOwnProperty('operator')){
        return OperaterAll(OperatorNode(left, left.left, left.right, left.operator),right, operator)
    }
    if(!left.hasOwnProperty('operator') && right.hasOwnProperty('operator')){
        return OperaterAll(left,OperatorNode(right, right.left, right.right, right.operator),operator)
    }
    // if(left.operator && right.operator){
    //     return OperatorNode(OperatorNode(left.left, left.right, left.operator),OperatorNode(right.left, right.right, right.operator), operator)
    // }
    var result, t, raw;
    result = OperaterAll(left.value, right.value, operator);

    switch (typeof result) {
        case "boolean","number":
            raw = result.toString();
            t = 'Literal';
            break;
        case "string":
            raw = result;
            t = 'Literal';
            break;
    }
    delete parent.left;
    delete parent.right;
    delete parent.operator;

    parent = {

    }
    return result
}

//判断是否是表达式
function isExpression(node) {
    if(node.type==='BinaryExpression'||node.type==='StringLiteral'||node.type==='NumericLiteral'||node.type==='BooleanLiteral'){
        return true
    }
    return false

}

function traverse1(jscode){
    var ast = babylon.parse(jscode);
    console.log(ast);
    traverse(ast, {
        BinaryExpression(path) {
            OperatorNode(path.node,path.node.left,path.node.right,path.node.operator)
        },

        ObjectProperty(path){
            if(t.isIdentifier(path.node.key,{
                name:"message"
            })){
                path.remove();
            }
        },
        SequenceExpression(path) {
            // console.log(path);
            console.log(path.node.expressions);

            // path.node.expressions[0].right.value = path.node.expressions[2].right.value
            // delete path.node.expressions[1];
            // console.log("1");
            //遍历表达式筛选并标记要删除的下标，过后再删除
            var globalObj = {};
            var deleteIndex = new Array();
            for (var e in path.node.expressions) {
                // delete
                var expre = path.node.expressions[e];

                // delete path.node.expressions[e];
                console.log(e,expre);
                // if(expre.right.operator){
                //     console.log(e);
                // }
                if (expre.type === 'AssignmentExpression') {
                    switch (expre.operator) {
                        case "=":
                            // globalObj[expre.left.name] = expre.right.value;

                            if(globalObj[expre.left.name]){
                                globalObj[expre.left.name] = expre.right.value;
                                deleteIndex.push(e);
                            }else{
                                globalObj[expre.left.name] = expre.right.value;
                            }
                            break
                        case "-=":
                            if(globalObj.hasOwnProperty(expre.left.name)){
                                //二元操作运算
                                if(expre.right.type==='BinaryExpression'){
                                    globalObj[expre.left.name] -= OperatorNode(expre.right,expre.right.left, expre.right.right, expre.operator)
                                }else if(expre.right.type==='CallExpression'){
                                    console.log(expre.right.callee);
                                    console.log(1);
                                }else{
                                    globalObj[expre.left.name] -= expre.right.value;
                                }
                            }
                            break
                        case "+=":
                            if(globalObj.hasOwnProperty(expre.left.name)){
                                //二元操作运算
                                if(expre.right.type==='BinaryExpression'){
                                    globalObj[expre.left.name] += OperatorNode(expre.right, expre.right.left, expre.right.right, expre.operator)
                                }else if(expre.right.type==='CallExpression'){
                                    console.log(expre.right.callee,expre.right.arguments);
                                    console.log(1);
                                }else{
                                    globalObj[expre.left.name] += expre.right.value;
                                }
                            }
                            break
                        case "/=":
                            if(globalObj[expre.left.name]){
                                globalObj[expre.left.name] /= expre.right.value;
                            }
                            break
                        case "*=":
                            if(globalObj[expre.left.name]){
                                globalObj[expre.left.name] *= expre.right.value;
                            }
                            break
                    }
                    // if(expre.operator==='='){
                    //     if (expre.right.type === 'StringLiteral' || expre.right.type === 'NumericLiteral'||expre.right.type==='BooleanLiteral') {
                    //         globalObj[expre.left.name] = {
                    //             index:e,
                    //             value:expre.right.value,
                    //         }
                    //     }
                    // }

                }
            }
            // delete path.node.expressions[1];
            // console.log(path.node.expressions);
            // path.remove();
            console.log(globalObj);
            console.log(deleteIndex);
            console.log(1);
        }
    });
    console.log(generate(ast, {}, jscode).code)
}

function traverse2(jscode) {
    var ast = esprima.parse(jscode);
    console.log(ast);
    // for(var i=0;i<ast.body.length;i++){
    //
    // }
    estraverse.traverse(ast, {
        enter: function (node, parent) {

            if(node.hasOwnProperty('type') && node.type==="BinaryExpression"){
                console.log("node:",node);
                console.log("parent:", parent);
                OperatorNode(node,node.left,node.right,node.operator)
                return estraverse.VisitorOption.Skip;
            }
        }

    });
    const code = escodegen.generate(ast);

    console.log(code);
}


function parseCode(jscode) {
    var AST = esprima.parse(jscode);
    console.log(AST.body);

    Ast = estraverse.replace(AST, {
        level: function (node, parent) {
            modifiednode = node;
            if (node.type === 'IfStatement') {
                if (node.consequent != null && node.consequent.type === 'ExpressionStatement')
                {
                    if (node.consequent.expression.type === 'Literal'){
                        modifiedNode['consequent'] = {
                            "type": "ExpressionStatement",
                            "expression": {
                                "type": "AssignmentExpression",
                                "operator": "=",
                                "left": {
                                    "type": "Identifier",
                                    "name": "result"
                                },
                                "right": node.consequent.expression
                            }
                        }
                    }
                    if (node.alternate != null && node.alternate.expression.type === 'Literal'){
                        modifiedNode['alternate'] = {
                            "type": "ExpressionStatement",
                            "expression": {
                                "type": "AssignmentExpression",
                                "operator": "=",
                                "left": {
                                    "type": "Identifier",
                                    "name": "result"
                                },
                                "right": node.alternate.expression
                            }
                        }
                    }
                }
            }

            return modifiednode;
        }
    });
    // function walkIn(ast) {
    //     estraverse.replace(ast, {
    //         leave: function (node,parent) {
    //             modifiednode = node;
    //
    //         }
    //     })
    // }
    //
    // function optimize(node) {
    //     console.log(node, node.id, node.body);
    //     if (node.operator === "==") {
    //         node.operator = "==="
    //     }
    // }
    //
    // walkIn(AST);
    //
    const code = escodegen.generate(AST);

    console.log(code);

}